/*
--------------------------------------------------------------------------------
				Ak-Lib. 
			 Project       	: Ak-Lib
			 Group         	: Ak-Lib R&D Team
			 Author        	: Ocean.Wang
			 Create Date 	: 05-01-2010
--------------------------------------------------------------------------------
Code Name 	:  A.K 	~v~
Description	:  Yet Another Cross-Platform Lib.
Cautions    	:
--------------------------------------------------------------------------------
Change History:
Version		: 0.1
Building 		: 05/01/10
10-05.01 first draft, build, debug and test.
--------------------------------------------------------------------------------
*/

#ifndef _INC_AK_LOCK_
#define	_INC_AK_LOCK_

#include "ak_types.h"

#ifdef __cplusplus
extern "C" {
#endif

#define _WAIT_FOREVER 			(-1)
#define _WAIT_NOWAIT 			( 1)

extern unsigned long Sys_Atomic_Inc(unsigned long *v, int i);

/* Linux */
#if 	_TARGET_OS == _OS_GNU
/*	---------------------------------------------------------------------------
**	We use the Build-In Func to implement Atomic OPs.
*/
#ifdef 	_SUPPORT_ATOMIC_OP
#define ATOMIC_INC(pAtomic) 						__sync_add_and_fetch(pAtomic, 1)
#define ATOMIC_DEC(pAtomic)							__sync_sub_and_fetch(pAtomic, 1)
#define ATOMIC_ADD(pAtomic, varVal) 				__sync_fetch_and_add(pAtomic, varVal)
#define ATOMIC_SET(pAtomic, varSet) 				__sync_lock_test_and_set(pAtomic, varSet)
#define ATOMIC_XCHG(pAtomic, varXchg) 				__sync_lock_test_and_set(pAtomic, varXchg)
#define ATOMIC_CMPXCHG(pAtomic, varComp, varXchg) 	__sync_val_compare_and_swap(pAtomic, varComp, varXchg)

#else
#define ATOMIC_INC(pAtomic) 						Sys_Atomic_Inc(pAtomic, 1)


#endif

/*	---------------------------------------------------------------------------
**	We use the Pthread Lib to implement the Semaphore for convenience .
** 	pthread_mutex is used as critical section protect.
** 	The Operation Marco is recommend to Use by App.
*/
/* 	Destroy Mutex/Cond/RwLock 	*/
#define SYS_DESTROY_MUTEX(vPSem) 	pthread_mutex_destroy(vPSem)
#define SYS_DESTROY_RWLOCK(vPLock)	pthread_rwlock_destroy(vPLock)


/* 	RW Lock */
typedef pthread_rwlock_t	_t_sysLockRW;
#define SYS_LOCK_RW_INIT(vPSemRW) 	pthread_rwlock_init(vPSemRW, NULL)
#define SYS_LOCK_RD_TAKE(vPSemRW) 	pthread_rwlock_rdlock(vPSemRW)
#define SYS_LOCK_WR_TAKE(vPSemRW) 	pthread_rwlock_wrlock(vPSemRW)
#define SYS_LOCK_RW_GIVE(vPSemRW)	pthread_rwlock_unlock(vPSemRW)

/* 	Sem M */
typedef pthread_mutex_t 	_t_sysSemM;
extern	void 	_Semaphore_MInit(_t_sysSemM * pSemM);
#define SYS_SEM_M_INIT(vPSemM) 	_Semaphore_MInit(vPSemM)
#define SYS_SEM_M_TAKE(vPSemM) 	pthread_mutex_lock(vPSemM)
#define SYS_SEM_M_GIVE(vPSemM) 	pthread_mutex_unlock(vPSemM)

/* Critical Section */
typedef pthread_mutex_t 	_t_sysCS;
#define SYS_INIT_CS(vPCS)			_Semaphore_MInit(vPCS)
#define SYS_ENTER_CS(vPCS) 		pthread_mutex_lock(vPCS)
#define SYS_LEAVE_CS(vPCS) 		pthread_mutex_unlock(vPCS)

/* 	Sem B */
typedef struct _t_sysSemB{
	pthread_mutex_t 	mutex;
	pthread_cond_t  	cond;
	int 				count;
	int 				reserv;
}_t_sysSemB;
extern	int 	_Semaphore_BTake(_t_sysSemB * pSemB, int timeout);
static __inline void 	_Semaphore_BInit(_t_sysSemB * pSemB)
{
	if(pSemB){
		pSemB->count = 0;
		pthread_mutex_init(&(pSemB->mutex), NULL);
		pthread_cond_init(&(pSemB->cond), NULL);
	}
}

#define SYS_SEM_B_INIT(vPSemB) 			_Semaphore_BInit(vPSemB)
#define SYS_SEM_B_TAKE(vPSemB, msWait) 	_Semaphore_BTake(vPSemB, msWait)

#define SYS_SEM_B_GIVE(vPSemB) \
do{\
	pthread_mutex_lock(&((vPSemB)->mutex)); \
    (vPSemB)->count = 1;\
    pthread_cond_signal(&((vPSemB)->cond)); \
    pthread_mutex_unlock(&((vPSemB)->mutex)); \
}while(0)


/* Windows */
#elif 	_TARGET_OS == _OS_WIN
/*	---------------------------------------------------------------------------
**	We use the Build-In Func to implement Atomic OPs.
*/
#define ATOMIC_INC(pAtomic) 						InterlockedIncrement((long *)(pAtomic))
#define ATOMIC_DEC(pAtomic)							InterlockedDecrement((long *)(pAtomic))
#define ATOMIC_ADD(pAtomic, varVal) 				InterlockedExchangeAdd(pAtomic, varVal)
#define ATOMIC_SET(pAtomic, varSet) 				InterlockedExchangePointer(pAtomic, varSet)
#define ATOMIC_XCHG(pAtomic, varXchg) 				InterlockedExchangePointer(pAtomic, varXchg)
#define ATOMIC_CMPXCHG(pAtomic, varComp, varXchg) 	InterlockedCompareExchangePointer(pAtomic, varXchg, varComp)

/* 	Destroy Mutex/Cond/RwLock 	*/
#define SYS_DESTROY_MUTEX(vPSem) 	DeleteCriticalSection(vPSem)
#define SYS_DESTROY_RWLOCK(vPLock)	DeleteCriticalSection(vPLock);

/* 	RW Lock */
typedef CRITICAL_SECTION	_t_sysLockRW;
#define SYS_LOCK_RW_INIT(vPSemRW) 	InitializeCriticalSection(vPSemRW)
#define SYS_LOCK_RD_TAKE(vPSemRW) 	EnterCriticalSection(vPSemRW)
#define SYS_LOCK_WR_TAKE(vPSemRW) 	EnterCriticalSection(vPSemRW)
#define SYS_LOCK_RW_GIVE(vPSemRW)		LeaveCriticalSection(vPSemRW)

/* 	Sem M */
typedef CRITICAL_SECTION 	_t_sysSemM;
#define SYS_SEM_M_INIT(vPSemM) 	InitializeCriticalSection(vPSemM)
#define SYS_SEM_M_TAKE(vPSemM) 	EnterCriticalSection(vPSemM)
#define SYS_SEM_M_GIVE(vPSemM) 	LeaveCriticalSection(vPSemM)

/* Critical Section */
typedef CRITICAL_SECTION 	_t_sysCS;
#define SYS_INIT_CS(vPCS)			InitializeCriticalSection(vPCS)
#define SYS_ENTER_CS(vPCS) 		EnterCriticalSection(vPCS)
#define SYS_LEAVE_CS(vPCS) 		LeaveCriticalSection(vPCS)

/* 	Sem B */
typedef HANDLE				_t_sysSemB;
static __inline void 	_Semaphore_BInit(_t_sysSemB * pSemB)
{
	if(pSemB){
		*pSemB = CreateEvent(NULL, 0, 0, NULL);
	}
	return;
}

#define SYS_SEM_B_INIT(vPSemB) 				_Semaphore_BInit(vPSemB)
#define SYS_SEM_B_TAKE(vPSemB, msWait) 		WaitForSingleObject(*(vPSemB), msWait)
#define SYS_SEM_B_GIVE(vPSemB) 				SetEvent(*(vPSemB))



#endif


#ifdef __cplusplus
}
#endif

#endif




